home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / net / ds3100.md / netLEXmit.c < prev   
C/C++ Source or Header  |  1992-12-18  |  18KB  |  628 lines

  1. /* 
  2.  * netLEXmit.c --
  3.  *
  4.  *    Routines to transmit packets on the LANCE interface.
  5.  *
  6.  * Copyright (C) 1989 Digital Equipment Corporation.
  7.  * Permission to use, copy, modify, and distribute this software and
  8.  * its documentation for any purpose and without fee is hereby granted,
  9.  * provided that the above copyright notice appears in all copies.  
  10.  * Digital Equipment Corporation makes no representations about the
  11.  * suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  */
  14.  
  15. #ifndef lint
  16. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/ds3100.md/netLEXmit.c,v 9.6 92/04/14 16:57:29 jhh Exp $ SPRITE (DECWRL)";
  17. #endif not lint
  18.  
  19. #include <sprite.h>
  20. #include <netLEInt.h>
  21. #include <sys.h>
  22. #include <vm.h>
  23. #include <list.h>
  24. #include <sync.h>
  25. #include <machMon.h>
  26.  
  27.  
  28. /*
  29.  *----------------------------------------------------------------------
  30.  *
  31.  * OutputPacket --
  32.  *
  33.  *    Assemble and output the packet in the given scatter/gather element.
  34.  *    The ethernet header contains the address of the destination host
  35.  *    and the higher level protocol type already.
  36.  *
  37.  * Results:
  38.  *    FAILURE if something went wrong.
  39.  *
  40.  * Side effects:
  41.  *    Transmit command list is modified to contain the packet.
  42.  *
  43.  *----------------------------------------------------------------------
  44.  */
  45. static ReturnStatus
  46. OutputPacket(etherHdrPtr, scatterGatherPtr, scatterGatherLength, statePtr)
  47.     Net_EtherHdr        *etherHdrPtr;    /* Ethernet header of packet.*/
  48.     register Net_ScatterGather    *scatterGatherPtr; /* Data portion of packet.*/
  49.     int                scatterGatherLength;/* Length of data portion 
  50.                              * gather array. */
  51.     NetLEState        *statePtr;        /* The interface state. */
  52. {
  53.     register short        *inBufPtr;
  54.     register volatile short    *outBufPtr;
  55.     register Address        descPtr;
  56.     register int        length;
  57.     unsigned    char        *leftOverBytePtr = (unsigned char *)NIL;
  58.     int                totLen;
  59.     int                i;
  60.  
  61.     descPtr = statePtr->xmitDescFirstPtr;
  62.  
  63.     /*
  64.      * Do a sanity check.
  65.      */
  66.     if (*BUF_TO_ADDR(descPtr, NET_LE_XMIT_STATUS1) & NET_LE_XMIT_CHIP_OWNED) {
  67.     printf("LE ethernet: Transmit buffer owned by chip.\n");
  68.     return (FAILURE);
  69.     }
  70.  
  71.     statePtr->transmitting = TRUE;
  72.     statePtr->curScatGathPtr = scatterGatherPtr;
  73.     etherHdrPtr->source = statePtr->etherAddress;
  74.     outBufPtr = (volatile short *)statePtr->xmitBufPtr;
  75.  
  76.     /* 
  77.      * Copy the packet into the xmit buffer.  Don't be general, be fast.
  78.      * First do the ethernet header.
  79.      */
  80.     inBufPtr = (short *)etherHdrPtr;
  81.     *outBufPtr = *inBufPtr;
  82.     *(outBufPtr + 2) = *(inBufPtr + 1);
  83.     *(outBufPtr + 4) = *(inBufPtr + 2);
  84.     *(outBufPtr + 6) = *(inBufPtr + 3);
  85.     *(outBufPtr + 8) = *(inBufPtr + 4);
  86.     *(outBufPtr + 10) = *(inBufPtr + 5);
  87.     *(outBufPtr + 12) = *(inBufPtr + 6);
  88.     outBufPtr += 14;
  89.     totLen = sizeof(Net_EtherHdr);
  90.  
  91.     /*
  92.      * Now do each element of the scatter/gather array.
  93.      */
  94.     for (i = 0; i < scatterGatherLength; i++,scatterGatherPtr++ ) {
  95.     unsigned char *bufAddr;
  96.  
  97.     length = scatterGatherPtr->length;
  98.     if (length == 0) {
  99.         continue;
  100.     }
  101.     totLen += length;
  102.     if (totLen > NET_ETHER_MAX_BYTES) {
  103.         printf("OutputPacket: Packet too large\n");
  104.         statePtr->curScatGathPtr = (Net_ScatterGather *)NIL;
  105.         statePtr->transmitting = FALSE;
  106.         return(FAILURE);
  107.     }
  108.     bufAddr = (unsigned char *)scatterGatherPtr->bufAddr;
  109.     /*
  110.      * Copy the element into the buffer.
  111.      */
  112.     if (leftOverBytePtr != (unsigned char *)NIL) {
  113.         /*
  114.          * We had one byte left over in the last piece of the packet.
  115.          * Concatenate this byte with the first byte of this piece.
  116.          */
  117.         *outBufPtr = *leftOverBytePtr | (*bufAddr << 8);
  118.         leftOverBytePtr = (unsigned char *)NIL;
  119.         bufAddr++;
  120.         outBufPtr += 2;
  121.         length--;
  122.     }
  123.  
  124. #define COPY_OUT(n) \
  125.     *(outBufPtr + n) = *(bufAddr + n) | (*(bufAddr + n + 1) << 8)
  126.  
  127. #define COPY_OUT2(n) \
  128.     *(outBufPtr + n) = *(short *)(bufAddr + n)
  129.  
  130.     if ((unsigned)bufAddr & 1) {
  131.         while (length > 64) {
  132.         COPY_OUT(0);  COPY_OUT(2);  COPY_OUT(4);  COPY_OUT(6);
  133.         COPY_OUT(8);  COPY_OUT(10); COPY_OUT(12); COPY_OUT(14);
  134.         COPY_OUT(16); COPY_OUT(18); COPY_OUT(20); COPY_OUT(22);
  135.         COPY_OUT(24); COPY_OUT(26); COPY_OUT(28); COPY_OUT(30);
  136.         COPY_OUT(32); COPY_OUT(34); COPY_OUT(36); COPY_OUT(38);
  137.         COPY_OUT(40); COPY_OUT(42); COPY_OUT(44); COPY_OUT(46);
  138.         COPY_OUT(48); COPY_OUT(50); COPY_OUT(52); COPY_OUT(54);
  139.         COPY_OUT(56); COPY_OUT(58); COPY_OUT(60); COPY_OUT(62);
  140.         outBufPtr += 64;
  141.         bufAddr += 64;
  142.         length -= 64;
  143.         }
  144.  
  145.         while (length > 16) {
  146.         COPY_OUT(0);  COPY_OUT(2);  COPY_OUT(4);  COPY_OUT(6);
  147.         COPY_OUT(8);  COPY_OUT(10); COPY_OUT(12); COPY_OUT(14);
  148.         outBufPtr += 16;
  149.         bufAddr += 16;
  150.         length -= 16;
  151.         }
  152.         while (length > 1) {
  153.         *outBufPtr = *bufAddr | (*(bufAddr + 1) << 8);
  154.         outBufPtr += 2;
  155.         bufAddr += 2;
  156.         length -= 2;
  157.         }
  158.     } else {
  159.         while (length >= 64) {
  160.         COPY_OUT2(0);  COPY_OUT2(2);  COPY_OUT2(4);  COPY_OUT2(6);
  161.         COPY_OUT2(8);  COPY_OUT2(10); COPY_OUT2(12); COPY_OUT2(14);
  162.         COPY_OUT2(16); COPY_OUT2(18); COPY_OUT2(20); COPY_OUT2(22);
  163.         COPY_OUT2(24); COPY_OUT2(26); COPY_OUT2(28); COPY_OUT2(30);
  164.         COPY_OUT2(32); COPY_OUT2(34); COPY_OUT2(36); COPY_OUT2(38);
  165.         COPY_OUT2(40); COPY_OUT2(42); COPY_OUT2(44); COPY_OUT2(46);
  166.         COPY_OUT2(48); COPY_OUT2(50); COPY_OUT2(52); COPY_OUT2(54);
  167.         COPY_OUT2(56); COPY_OUT2(58); COPY_OUT2(60); COPY_OUT2(62);
  168.         outBufPtr += 64;
  169.         bufAddr += 64;
  170.         length -= 64;
  171.         }
  172.  
  173.         while (length >= 16) {
  174.         COPY_OUT2(0);  COPY_OUT2(2);  COPY_OUT2(4);  COPY_OUT2(6);
  175.         COPY_OUT2(8);  COPY_OUT2(10); COPY_OUT2(12); COPY_OUT2(14);
  176.         outBufPtr += 16;
  177.         bufAddr += 16;
  178.         length -= 16;
  179.         }
  180.         while (length > 1) {
  181.         *outBufPtr = *(short *)bufAddr;
  182.         outBufPtr += 2;
  183.         bufAddr += 2;
  184.         length -= 2;
  185.         }
  186.     }
  187.     if (length == 1) {
  188.         leftOverBytePtr = bufAddr;
  189.     }
  190.     }
  191.     if (leftOverBytePtr != (unsigned char *)NIL) {
  192.     *outBufPtr = *leftOverBytePtr;
  193.     }
  194.  
  195.     /*
  196.      * Add the buffer to the ring.
  197.      */
  198.     if (totLen < NET_ETHER_MIN_BYTES) {
  199.     totLen = NET_ETHER_MIN_BYTES;
  200.     }
  201.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_SIZE) = -totLen;
  202.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_ADDR_LOW) = 
  203.             BUF_TO_CHIP_ADDR(statePtr->xmitBufPtr) & 0xFFFF;
  204.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1) =
  205.         ((BUF_TO_CHIP_ADDR(statePtr->xmitBufPtr) >> 16) & 
  206.             NET_LE_XMIT_BUF_ADDR_HIGH) |
  207.             NET_LE_XMIT_START_OF_PACKET | 
  208.             NET_LE_XMIT_END_OF_PACKET |
  209.             NET_LE_XMIT_CHIP_OWNED;
  210.  
  211.     /*
  212.      * Give the chip a little kick.
  213.      */
  214.     *statePtr->regAddrPortPtr = NET_LE_CSR0_ADDR;
  215.     *statePtr->regDataPortPtr =
  216.         (NET_LE_CSR0_XMIT_DEMAND | NET_LE_CSR0_INTR_ENABLE);
  217.     return (SUCCESS);
  218.  
  219. }
  220.  
  221.  
  222.  
  223. /*
  224.  *----------------------------------------------------------------------
  225.  *
  226.  * AllocateXmitMem --
  227.  *
  228.  *    Allocate kernel memory for transmission ring.    
  229.  *
  230.  * Results:
  231.  *    None.
  232.  *
  233.  * Side effects:
  234.  *    Device state structure is updated.
  235.  *
  236.  *----------------------------------------------------------------------
  237.  */
  238. static void
  239. AllocateXmitMem(statePtr)
  240.     NetLEState        *statePtr;     /* State of the interface. */
  241. {
  242.     /*
  243.      * Allocate a transmission buffer descriptor.  
  244.      * The descriptor must start on an 8-byte boundary.  
  245.      */
  246.     statePtr->xmitDescFirstPtr = NetLEMemAlloc(NET_LE_XMIT_DESC_SIZE, FALSE);
  247.  
  248.     /*
  249.      * Allocate a buffer for a transmitted packet.
  250.      */
  251.     statePtr->xmitBufPtr = NetLEMemAlloc(NET_ETHER_MAX_BYTES, TRUE);
  252.  
  253.     statePtr->xmitMemAllocated = TRUE;
  254. }
  255.  
  256.  
  257. /*
  258.  *----------------------------------------------------------------------
  259.  *
  260.  * NetLEXmitInit --
  261.  *
  262.  *    Initialize the transmission queue structures.  This includes setting
  263.  *    up the transmission ring buffers.
  264.  *
  265.  * Results:
  266.  *    None.
  267.  *
  268.  * Side effects:
  269.  *    The transmission ring is initialized.
  270.  *
  271.  *----------------------------------------------------------------------
  272.  */
  273. void
  274. NetLEXmitInit(statePtr)
  275.     NetLEState        *statePtr;     /* State of the interface. */
  276. {
  277.     Address    descPtr;
  278.  
  279.     if (!statePtr->xmitMemAllocated) {
  280.     AllocateXmitMem(statePtr);
  281.     }
  282.     statePtr->xmitMemInitialized = TRUE;
  283.  
  284.     /*
  285.      * Initialize the state structure to point to the ring. xmitDescFirstPtr
  286.      * is set by AllocateXmitMem() and never moved.
  287.      */
  288.     statePtr->xmitDescLastPtr = statePtr->xmitDescFirstPtr;
  289.     statePtr->xmitDescNextPtr = statePtr->xmitDescFirstPtr;
  290.  
  291.     descPtr = statePtr->xmitDescFirstPtr;
  292.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_BUF_ADDR_LOW) = 0;
  293.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1) = 0;
  294.     *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS2) = 0;
  295.  
  296.     statePtr->transmitting = FALSE;
  297.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  298. }
  299.  
  300.  
  301. /*
  302.  *----------------------------------------------------------------------
  303.  *
  304.  * NetLEXmitDone --
  305.  *
  306.  *    This routine will process a completed transmit command.  It will
  307.  *    check for errors and update the transmission ring pointers.
  308.  *
  309.  * Results:
  310.  *    FAILURE if problem is found.
  311.  *
  312.  * Side effects:
  313.  *    None.
  314.  *
  315.  *----------------------------------------------------------------------
  316.  */
  317.  
  318. ReturnStatus
  319. NetLEXmitDone(statePtr)
  320.     NetLEState        *statePtr;     /* State of the interface. */
  321. {
  322.     register    NetXmitElement    *xmitElementPtr;
  323.     register    Address        descPtr;
  324.     ReturnStatus        status;
  325.     unsigned            status1;
  326.     unsigned            status2;
  327.  
  328.     descPtr = (Address)statePtr->xmitDescNextPtr;
  329.  
  330.     /*
  331.      * Reset the interrupt.
  332.      */
  333.     *statePtr->regAddrPortPtr = NET_LE_CSR0_ADDR;
  334.     *statePtr->regDataPortPtr = 
  335.         (NET_LE_CSR0_XMIT_INTR | NET_LE_CSR0_INTR_ENABLE);
  336.  
  337.     /*
  338.      * If there is nothing that is currently being sent then something is
  339.      * wrong.
  340.      */
  341.     if (statePtr->curScatGathPtr == (Net_ScatterGather *) NIL) {
  342.     printf( "NetLEXmitDone: No current packet\n.");
  343.     return (FAILURE);
  344.     }
  345.  
  346.     status1 = *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS1);
  347.     status2 = *BUF_TO_ADDR(descPtr,NET_LE_XMIT_STATUS2);
  348.     if (status1 & NET_LE_XMIT_CHIP_OWNED) {
  349.     printf("netLE: Bogus transmit interrupt. Buffer owned by chip.\n");
  350.     return (FAILURE);
  351.     }
  352.  
  353.     /*
  354.      * Check for errors.
  355.      */
  356.     if (status1 & NET_LE_XMIT_ERROR) {
  357.     statePtr->stats.xmitPacketsDropped++;
  358.     if (status2 & NET_LE_XMIT_LOST_CARRIER) {
  359.         printf("LE ethernet: Lost carrier.\n");
  360.     }
  361.     /*
  362.      * Loss of carrier seems to also causes late collision.
  363.      * Print only one of the messages.
  364.      */
  365.     if ((status2 & NET_LE_XMIT_LATE_COLLISION) && 
  366.         !(status2 & NET_LE_XMIT_LOST_CARRIER)) {
  367.         printf("LE ethernet: Transmit late collision.\n");
  368.     }
  369.     if (status2 & NET_LE_XMIT_RETRY_ERROR) {
  370.         statePtr->stats.xmitCollisionDrop++;
  371.         statePtr->stats.collisions += 16;
  372.         printf("LE ethernet: Too many collisions.\n");
  373.     }
  374.     if (status2 & NET_LE_XMIT_UNDER_FLOW_ERROR) {
  375.         printf("LE ethernet: Memory underflow error.\n");
  376.         return (FAILURE);
  377.     }
  378.     }
  379.     if (status2 & NET_LE_XMIT_BUFFER_ERROR) {
  380.     printf("LE ethernet: Transmit buffering error.\n");
  381.     return (FAILURE);
  382.     }
  383.     if (status1 & NET_LE_XMIT_ONE_RETRY) {
  384.     statePtr->stats.collisions++;
  385.     }
  386.     if (status1 & NET_LE_XMIT_RETRIES) {
  387.     /*
  388.      * Two is more than one.  
  389.      */
  390.     statePtr->stats.collisions += 2;    /* Only a guess. */
  391.     }
  392.  
  393.     statePtr->stats.packetsSent++;
  394.  
  395.     /*
  396.      * Mark the packet as done.
  397.      */
  398.     statePtr->curScatGathPtr->done = TRUE;
  399.     if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
  400.     NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
  401.     }
  402.  
  403.     /*
  404.      * If there are more packets to send then send the first one on
  405.      * the queue.  Otherwise there is nothing being transmitted.
  406.      */
  407.     status = SUCCESS;
  408.     if (!List_IsEmpty(statePtr->xmitList)) {
  409.     xmitElementPtr = (NetXmitElement *) List_First(statePtr->xmitList);
  410.     status = OutputPacket(xmitElementPtr->etherHdrPtr,
  411.              xmitElementPtr->scatterGatherPtr,
  412.              xmitElementPtr->scatterGatherLength, statePtr);
  413.     List_Move((List_Links *) xmitElementPtr, 
  414.           LIST_ATREAR(statePtr->xmitFreeList));
  415.     } else {
  416.     statePtr->transmitting = FALSE;
  417.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  418.     }
  419.     return (status);
  420. }
  421.  
  422.  
  423. /*
  424.  *----------------------------------------------------------------------
  425.  *
  426.  * NetLEOutput --
  427.  *
  428.  *    Output a packet.  The procedure is to either put the packet onto the 
  429.  *    queue of outgoing packets if packets are already being sent, or 
  430.  *    otherwise to send the packet directly.  The elements of the scatter 
  431.  *    array which come into this routine must satisfy the following two 
  432.  *    properties:
  433.  *
  434.  *
  435.  * Results:
  436.  *    None.
  437.  *
  438.  * Side effects:
  439.  *    Queue of packets modified.
  440.  *
  441.  *----------------------------------------------------------------------
  442.  */
  443.  
  444. ReturnStatus
  445. NetLEOutput(interPtr, etherHdrPtr, scatterGatherPtr, scatterGatherLength, rpc,
  446.     statusPtr)
  447.     Net_Interface    *interPtr;    /* The network interface. */
  448.     Net_EtherHdr    *etherHdrPtr;    /* Ethernet header for the packet. */
  449.     register    Net_ScatterGather    *scatterGatherPtr; /* Data portion of 
  450.                                 * the packet. */
  451.     int            scatterGatherLength;    /* Length of data portion gather
  452.                          * array. */
  453.     Boolean        rpc;        /* Is this an rpc packet? */
  454.     ReturnStatus    *statusPtr;    /* Status from sending packet. */
  455. {
  456.     register    NetXmitElement        *xmitPtr;
  457.     ReturnStatus            status;
  458.     NetLEState                *statePtr;
  459.  
  460.     statePtr = (NetLEState *) interPtr->interfaceData;
  461.     DISABLE_INTR();
  462.  
  463.     statePtr->stats.packetsOutput++;
  464.  
  465.     /*
  466.      * See if the packet is for us.  In this case just copy in the packet
  467.      * and call the higher level routine.
  468.      */
  469.  
  470.     if (!Net_EtherAddrCmp(statePtr->etherAddress, etherHdrPtr->destination)) {
  471.     int i, length;
  472.  
  473.         length = sizeof(Net_EtherHdr);
  474.         for (i = 0; i < scatterGatherLength; i++) {
  475.             length += scatterGatherPtr[i].length;
  476.         }
  477.  
  478.         if (length <= NET_ETHER_MAX_BYTES) {
  479.         register Address bufPtr;
  480.  
  481.         etherHdrPtr->source = statePtr->etherAddress;
  482.  
  483.         bufPtr = (Address)statePtr->loopBackBuffer;
  484.         bcopy((Address)etherHdrPtr, bufPtr, sizeof(Net_EtherHdr));
  485.         bufPtr += sizeof(Net_EtherHdr);
  486.             Net_GatherCopy(scatterGatherPtr, scatterGatherLength, bufPtr);
  487.  
  488.         Net_Input(interPtr,(Address)statePtr->loopBackBuffer, length);
  489.         }
  490.  
  491.         scatterGatherPtr->done = TRUE;
  492.     if (statusPtr != (ReturnStatus *) NIL) {
  493.         *statusPtr = SUCCESS;
  494.     }
  495.  
  496.     ENABLE_INTR();
  497.     return SUCCESS;
  498.     }
  499.  
  500.     /*
  501.      * If no packet is being sent then go ahead and send this one.
  502.      */
  503.  
  504.     if (!statePtr->transmitting) {
  505.     status = 
  506.         OutputPacket(etherHdrPtr, scatterGatherPtr, scatterGatherLength,
  507.             statePtr);
  508.     if (status != SUCCESS) {
  509.         NetLERestart(statePtr);
  510.     }
  511.     if (statusPtr != (ReturnStatus *) NIL) {
  512.         *statusPtr = status;
  513.     }
  514.     ENABLE_INTR();
  515.     return status;
  516.     }
  517.  
  518.     /*
  519.      * There is a packet being sent so this packet has to be put onto the
  520.      * transmission queue.  Get an element off of the transmission free list.  
  521.      * If none available then drop the packet.
  522.      */
  523.  
  524.     if (List_IsEmpty(statePtr->xmitFreeList)) {
  525.         scatterGatherPtr->done = TRUE;
  526.     ENABLE_INTR();
  527.     return FAILURE;
  528.     }
  529.  
  530.     xmitPtr = 
  531.     (NetXmitElement *)List_First((List_Links *) statePtr->xmitFreeList);
  532.  
  533.     List_Remove((List_Links *) xmitPtr);
  534.  
  535.     /*
  536.      * Initialize the list element.
  537.      */
  538.     xmitPtr->etherHdrPtr = etherHdrPtr;
  539.     xmitPtr->scatterGatherPtr = scatterGatherPtr;
  540.     xmitPtr->scatterGatherLength = scatterGatherLength;
  541.  
  542.     /* 
  543.      * Put onto the transmission queue.
  544.      */
  545.     List_Insert((List_Links *) xmitPtr, LIST_ATREAR(statePtr->xmitList)); 
  546.  
  547.     if (statusPtr != (ReturnStatus *) NIL) {
  548.     *statusPtr = SUCCESS;
  549.     }
  550.     ENABLE_INTR();
  551.     return SUCCESS;
  552. }
  553.  
  554.  
  555. /*
  556.  *----------------------------------------------------------------------
  557.  *
  558.  * NetLEXmitDrop --
  559.  *
  560.  *    Drop the current packet.  Called at the beginning of the
  561.  *    restart sequence, before curScatGathPtr is reset to NIL.
  562.  *
  563.  * Results:
  564.  *    None.
  565.  *
  566.  * Side effects:
  567.  *    Current scatter gather pointer is reset and processes waiting
  568.  *    for synchronous output are notified.
  569.  *
  570.  *----------------------------------------------------------------------
  571.  */
  572. void
  573. NetLEXmitDrop(statePtr)
  574.     NetLEState        *statePtr;     /* State of the interface. */
  575. {
  576.     if (statePtr->curScatGathPtr != (Net_ScatterGather *) NIL) {
  577.     statePtr->curScatGathPtr->done = TRUE;
  578.     if (statePtr->curScatGathPtr->mutexPtr != (Sync_Semaphore *) NIL) {
  579.         NetOutputWakeup(statePtr->curScatGathPtr->mutexPtr);
  580.     }
  581.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  582.     }
  583. }
  584.  
  585.  
  586. /*
  587.  *----------------------------------------------------------------------
  588.  *
  589.  * NetLEXmitRestart --
  590.  *
  591.  *    Restart transmission of packets after a chip reset.
  592.  *
  593.  * Results:
  594.  *    None.
  595.  *
  596.  * Side effects:
  597.  *    Current scatter gather pointer is reset and new packets may be
  598.  *    sent out.
  599.  *
  600.  *----------------------------------------------------------------------
  601.  */
  602. void
  603. NetLEXmitRestart(statePtr)
  604.     NetLEState        *statePtr;     /* State of the interface. */
  605. {
  606.     NetXmitElement    *xmitElementPtr;
  607.     ReturnStatus    status;
  608.  
  609.     /*
  610.      * Start output if there are any packets queued up.
  611.      */
  612.     if (!List_IsEmpty(statePtr->xmitList)) {
  613.     xmitElementPtr = (NetXmitElement *) List_First(statePtr->xmitList);
  614.     status = OutputPacket(xmitElementPtr->etherHdrPtr,
  615.              xmitElementPtr->scatterGatherPtr,
  616.              xmitElementPtr->scatterGatherLength,
  617.              statePtr);
  618.     if (status != SUCCESS) {
  619.         panic("LE ethernet: Can not output first packet on restart.\n");
  620.     }
  621.     List_Move((List_Links *) xmitElementPtr, 
  622.           LIST_ATREAR(statePtr->xmitFreeList));
  623.     } else {
  624.     statePtr->transmitting = FALSE;
  625.     statePtr->curScatGathPtr = (Net_ScatterGather *) NIL;
  626.     }
  627. }
  628.